/** Binds the Cairo API directly. Usually won't be used by programs, just
  * internally in vanilla.graphics.drawing.
  *
  * I have documented this to some extent, but not much - It is only
  * used by vanilla.graphics.drawing and maybe some SDL code at present.
  *
  * Copyright: Same as cairo.h in Cairo's distribution.
  *
  * See_Also: cairo.h
  *           cairographics.org (API documentation)
  *           vanilla.graphics.drawing
  */
module dice.render.cairo;

extern(C):

struct Pattern;
struct Context;
struct Surface;

/** Gets the version */
int cairo_version ();
char* cairo_version_string ();

/** Binds cairo_matrix_t.
  *
  * Holds an affine transformation, such as scale, rotation, shear,
  * or a combination of those. The transformation of a point (x, y)
  * is given by:
  * -------------------------------
  *  x_new = xx * x + xy * y + x0;
  *  y_new = yx * x + yy * y + y0;
  * -------------------------------
  */
struct Matrix
{
	double xx;	/// xx component
	double yx;	/// yx component
	double xy;	/// xy component
	double yy;	/// yy component
	double x0;	/// x component
	double y0;	/// y component
}

/** Binds cairo_status_t enum */
enum Status
{
    SUCCESS = 0,
    NO_MEMORY,
    INVALID_RESTORE,
    INVALID_POP_GROUP,
    NO_CURRENT_POINT,
    INVALID_MATRIX,
    INVALID_STATUS,
    NULL_POINTER,
    INVALID_STRING,
    INVALID_PATH_DATA,
    READ_ERROR,
    WRITE_ERROR,
    SURFACE_FINISHED,
    SURFACE_TYPE_MISMATCH,
    PATTERN_TYPE_MISMATCH,
    INVALID_CONTENT,
    INVALID_FORMAT,
    INVALID_VISUAL,
    FILE_NOT_FOUND,
    INVALID_DASH
}

/** Create a Cairo context for given surface */
Context* cairo_create (Surface* target);

/** Reference a context */
Context* cairo_reference (Context* cr);

/** Destroy a context */
void cairo_destroy (Context* cr);

/** Save a context */
void cairo_save (Context* cr);

/** Restore a context */
void cairo_restore (Context* cr);

/** Binds cairo_operator_t */
enum Operator
{
    CLEAR,

    SOURCE,
    OVER,
    IN,
    OUT,
    ATOP,

    DEST,
    DEST_OVER,
    DEST_IN,
    DEST_OUT,
    DEST_ATOP,

    XOR,
    ADD,
    SATURATE
}

/** Set operator */
void cairo_set_operator (Context* cr, Operator op);

/** Set source */
void cairo_set_source (Context* cr, Pattern* source);

/** Set RGB source */
void cairo_set_source_rgb (Context* cr,
                           double red, double green,
                           double blue);

/** Set RGBA source */
void cairo_set_source_rgba (Context* cr,
                            double red, double green,
                            double blue, double alpha);

/** Binds cairo_antialias_t */
enum AntiAlias
{
    DEFAULT,
    NONE,
    GRAY,
    SUBPIXEL
}

/** Boolean type */
alias int Bool;

/** Binds cairo_fill_rule_t */
enum FillRule
{
	WINDING,
	EVEN_ODD
}

/** Sets fill rule */
void cairo_set_fill_rule (Context* cr, FillRule f);

/** Sets line width */
void cairo_set_line_width (Context* cr, double width);

/** Binds cairo_line_cap_t */
enum LineCap
{
	BUTT,
	ROUND,
	SQUARE
}

/** Sets line cap */
void cairo_set_line_cap (Context* cr, LineCap lc);

/** Wraps cairo_line_join_t */
enum LineJoin
{
	MITER,
	ROUND,
	BEVEL
}

/** Sets line join */
void cairo_set_line_join (Context* cr, LineJoin lj);

/** Sets dashes */
void cairo_set_dash (Context* cr, double* dashes,
                     int num_dashes, double offset);

/** Sets miter limit */
void cairo_set_miter_limit (Context* cr, double limit);

/** Translate */
void cairo_translate (Context* cr, double tx, double ty);

/** Scale */
void cairo_scale (Context* cr, double sx, double sy);

/** Rotate */
void cairo_rotate (Context* cr, double angle);

/** Transform */
void cairo_transform (Context* cr, Matrix* m);

/** Sets matrix */
void cairo_set_matrix (Context* cr, Matrix* m);

/** Identity matrix [??] */
void cairo_identity_matrix (Context* cr);

/** User to device */
void cairo_user_to_device (Context* cr,
                           double* x, double* y);

/** User to device [distance] */
void cairo_user_to_device_distance (Context* cr,
                                    double* dx,
                                    double* dy);

/** Device to user */
void cairo_device_to_user (Context* cr,
                           double* x, double* y);

/** Device to user [distance] */
void cairo_device_to_user_distance (Context* cr,
                                    double* dx,
                                    double* dy);

/** Path creation */
void cairo_new_path (Context* cr);

/** Move to */
void cairo_move_to (Context* cr, double x, double y);

/** Line to */
void cairo_line_to (Context* cr, double x, double y);

/** Curve to */
void cairo_curve_to (Context* cr,
                     double x1, double y1,
                     double x2, double y2,
                     double x3, double y3);

/** Arc */
void cairo_arc (Context* cr, double xc, double yc,
                double radius,
                double angle1, double angle2);

/** Negative arc */
void cairo_arc_negative (Context* cr,
                         double xc, double yc,
                         double radius,
                         double angle1, double angle2);

/** Relative move to */
void cairo_rel_move_to (Context* cr, double x, double y);

/** Relative line to */
void cairo_rel_line_to (Context* cr, double x, double y);

/** Relative curve to */
void cairo_rel_curve_to (Context* cr,
                         double x1, double y1,
                         double x2, double y2,
                         double x3, double y3);

/** Rectangle */
void cairo_rectangle (Context* cr,
                      double x, double y,
                      double width, double height);

/** Close path */
void cairo_close_path (Context* cr);

/** Paint */
void cairo_paint (Context* cr);

/** Paint with alpha */
void cairo_paint_with_alpha (Context* cr, double alpha);

/** Mask */
void cairo_mask (Context* cr, Pattern *p);

/** Mask surface */
void cairo_mask_surface (Context* cr,
                         Surface* s,
                         double s_x, double s_y);

/** Stroke */
void cairo_stroke (Context* cr);

/** Stroke (preserve) */
void cairo_stroke_preserve (Context* cr);

/** Fill */
void cairo_fill (Context* cr);

/** Fill (preserve) */
void cairo_fill_preserve (Context* cr);

/** Copy page */
void cairo_copy_page (Context* cr);

/** Show page */
void cairo_show_page (Context* cr);

/** Inside stroke? */
Bool cairo_in_stroke (Context* cr, double x, double y);

/** Inside fill? */
Bool cairo_in_fill (Context* cr, double x, double y);

/** Get rectangular extents of stroke */
void cairo_stroke_extents (Context* cr,
                           double* x1, double* y1,
                           double* x2, double* y2);

/** Get rectangular extents of fill */
void cairo_fill_extents (Context* cr,
                         double* x1, double* y1,
                         double* x2, double* y2);

/** Reset clipping */
void cairo_reset_clip (Context* cr);

/** Clip */
void cairo_clip (Context* cr);

/** Clip (preserve) */
void cairo_clip_preserve (Context* cr);

/** TODO: FONTS - cairo.h line 556 to 934 */

struct ScaledFont;
struct FontFace;

struct Glyph
{
	uint index;
	double x;
	double y;
}

struct TextExtents
{
	double x_bearing;
	double y_bearing;
	double width;
	double height;
	double x_advance;
	double y_advance;
}

struct FontExtents
{
	double ascent;
	double descent;
	double height;
	double max_x_advance;
	double max_y_advance;
}

enum FontSlant
{
	NORMAL,
	ITALIC,
	OBLIQUE
}

enum FontWeight
{
	NORMAL,
	BOLD
}

enum SubPixelOrder
{
	DEFAULT,
	RGB,
	BGR,
	VRGB,
	VGBR
}

enum HintStyle
{
	DEFAULT,
	NONE,
	SLIGHT,
	MEDIUM,
	FULL
}

enum HintMetrics
{
	DEFAULT,
	OFF,
	ON
}

struct FontOptions;

FontOptions* cairo_font_options_create ();
FontOptions* cairo_font_options_copy (FontOptions* original);
void cairo_font_options_destroy (FontOptions* fo);
Status cairo_font_options_status (FontOptions* fo);
void cairo_font_options_merge (FontOptions* a, FontOptions* b);
int cairo_font_options_equal (FontOptions* a, FontOptions* b);
uint cairo_font_options_hash (FontOptions* fo);
void cairo_font_options_set_antialias (FontOptions* fo, AntiAlias aa);
AntiAlias cairo_font_options_get_antialias (FontOptions* fo);
void cairo_font_options_set_subpixel_order (FontOptions* fo, SubPixelOrder so);
SubPixelOrder cairo_font_options_get_subpixel_order (FontOptions* fo);
void cairo_font_options_set_hint_style (FontOptions* fo, HintStyle hs);
HintStyle cairo_font_options_get_hint_style (FontOptions* fo);
void cairo_font_options_set_hint_metrics (FontOptions* fo, HintMetrics hm);
HintMetrics cairo_font_options_get_hint_metrics (FontOptions* fo);

void cairo_select_font_face (Context* cr, char* face, FontSlant slant, FontWeight weight);
void cairo_set_font_size (Context* cr, double sz);
void cairo_set_font_matrix (Context* cr, Matrix* m);
void cairo_get_font_matrix (Context* cr, Matrix* m);
void cairo_set_font_options (Context* cr, FontOptions* fo);
void cairo_get_font_options (Context* cr, FontOptions* fo);
void cairo_show_text (Context* cr, char* utf8);
void cairo_show_glyphs (Context* cr, Glyph* glyphs, int count);
FontFace* cairo_get_font_face (Context* cr);
void cairo_font_extents (Context* cr, FontExtents* fe);
void cairo_set_font_face (Context* cr, FontFace* ff);
void cairo_text_extents (Context* cr, char* utf8, TextExtents* te);
void cairo_glyph_extents (Context* cr, Glyph* glyphs, int count, TextExtents* te);
void cairo_text_path (Context* cr, char* utf8);
void cairo_glyph_path (Context* cr, Glyph* glyphs, int count);

FontFace* cairo_font_face_reference (FontFace* ff);
void cairo_font_face_destroy (FontFace* ff);
Status cairo_font_face_status (FontFace* ff);
//Status set user data

ScaledFont* cairo_scaled_font_create (FontFace* ff, Matrix* m, Matrix* ctm, FontOptions* fo);
ScaledFont* cairo_scaled_font_reference (ScaledFont* sf);
void cairo_scaled_font_destroy (ScaledFont* sf);
Status cairo_scaled_font_status (ScaledFont* sf);
void cairo_scaled_font_extents (ScaledFont* sf, FontExtents* fe);
void cairo_scaled_font_glyph_extents (ScaledFont* sf, Glyph* glyphs, int count, TextExtents* te);

/** Get operator */
Operator cairo_get_operator (Context* cr);

/** Get source */
Pattern* cairo_get_source (Context* cr);

/** Get tolerance */
double cairo_get_tolerance (Context* cr);

/** Get anti-aliasing */
AntiAlias cairo_get_antialias (Context* cr);

/** Get current point */
void cairo_get_current_point (Context* cr,
                              double* x, double* y);

/** Get fill rule */
FillRule cairo_get_fill_rule (Context* cr);

/** Get line width */
double cairo_get_line_width (Context* cr);

/** Get line cap */
LineCap cairo_get_line_cap (Context* cr);

/** Get line join */
LineJoin cairo_get_line_join (Context* cr);

/** Get miter limit */
double cairo_get_miter_limit (Context* cr);

/** Binds cairo_data_type_t */
enum PathDataType
{
	MOVE_TO,
	LINE_TO,
	CURVE_TO,
	CLOSE_PATH
}

struct Foo
{
	PathDataType type;
	int length;
}

struct Bar
{
	double x, y;
}

/** Binds cairo_path_data_t */
union PathData
{
	Foo header;
	Bar point;
}

/** Binds cairo_path_t */
struct Path
{
	Status status;
	PathData* data;
	int num_data;
}

/** Copy path */
Path* cairo_copy_path (Context* cr);

/** Copy path (flat) */
Path* cairo_copy_path_flat (Context* cr);

/** Append path */
void cairo_append_path (Context* cr, Path* p);

/** Destroy path */
void cairo_path_destroy (Path* p);

/** Check error status */
Status cairo_status (Context* cr);

/** Gets string representation of a status */
char* cairo_status_to_string (Status s);

/** Binds cairo_content_t */
enum Content
{
	COLOR = 0x1000,
	ALPHA = 0x2000,
	COLOR_ALPHA = 0x3000
}

/** Create a similar surface */
Surface* cairo_surface_create_similar (Surface* other,
		Content content,
		int width, int height);

/** Reference surface */
Surface* cairo_surface_reference (Surface* s);

/** Destroy surface */
void cairo_surface_destroy (Surface* s);

/** Gets the status of a surface */
Status cairo_surface_status (Surface* s);

/** Finish surface [??] */
void cairo_surface_finish (Surface* s);

// Let's just assume PNG support is compiled in
// TODO: add cairo_write_to_png_stream
//version(cairo_png)
//{
/** Write surface to PNG file */
Status cairo_surface_write_to_png (Surface* s,
                                   char* filename);
//} //version(cairo_png)

// TODO: add set/get_user_data

/** Mummy, Mummy! can I lick the bowl? */
void cairo_surface_flush (Surface *s);

/** You've been a very dirty surface */
void cairo_surface_mark_dirty (Surface* s);

/** You've been a very dirty rectangular area */
void cairo_surface_mark_dirty_rectangle (Surface* s,
		int x, int y,
		int width, int height);

/** Set device offset */
void cairo_surface_set_device_offset (Surface* s,
		double x_offset, double y_offset);

/** Image format (binds cairo_format_t) */
enum Format
{
	ARGB32,	/// 32bit alpha/red/green/blue
	RGB24,	/// 24bit red/green/blue
	A8,	/// 8bit intensity/alpha only
	A1	/// 1bit opaque or transparent
}

/** Create image surface */
Surface* cairo_image_surface_create (Format format,
		int width, int height);

/** Create an image surface, with data given */
Surface* cairo_image_surface_create_for_data
		(char* data, Format format,
		 int width, int height, int stride);

/** Get surface width */
int cairo_image_surface_get_width (Surface* s);

/** Get surface height */
int cairo_image_surface_get_height (Surface* s);

// TODO: add ...from_png_stream
//version(cairo_png)
//{
/** Create a surface from a PNG file */
Surface* cairo_image_surface_create_from_png
		(char* filename);
//} // version(cairo_png)

/** Create pattern from RGB */
Pattern* cairo_pattern_create_rgb (double red,
                                   double green,
                                   double blue);

/** Create pattern from RGBA */
Pattern* cairo_pattern_create_rgba (double red,
                                    double green,
                                    double blue,
                                    double alpha);

/** Create pattern for surface */
Pattern* cairo_pattern_create_for_surface (Surface* s);

/** Create linear pattern */
Pattern* cairo_pattern_create_linear
		(double x0, double y0,
		 double x1, double y1);

/** Create radial pattern */
Pattern* cairo_pattern_create_radial
		(double cx0, double cy0, double radius0,
		 double cx1, double cy1, double radius1);

/** Reference pattern */
Pattern* cairo_pattern_reference (Pattern* p);

/** Destroy pattern */
void cairo_pattern_destroy (Pattern* p);

/** Gets pattern status */
Status cairo_pattern_status (Pattern* p);

/** Add colour stop RGB */
void cairo_pattern_add_color_stop_rgb
		(Pattern* p, double offset,
		 double red, double green, double blue);

/** Add colour stop RGBA */
void cairo_pattern_add_color_stop_rgba
		(Pattern* p, double offset,
		 double red, double green,
		 double blue, double alpha);

/** Set pattern matrix */
void cairo_pattern_set_matrix (Pattern* p,
                               Matrix* m);

/** Get pattern matrix */
void cairo_pattern_get_matrix (Pattern* p,
                               Matrix* m);

/** Binds cairo_extend_t */
enum Extend
{
	NONE,
	REPEAT,
	REFLECT
}

/** Set pattern extend */
void cairo_pattern_set_extend (Pattern* p, Extend e);

/** Get pattern extend */
Extend cairo_pattern_get_extend (Pattern* p);

/** Binds cairo_filter_t */
enum Filter
{
	FAST,
	GOOD,
	BEST,
	NEAREST,
	BILINEAR,
	GAUSSIAN
}

/** Sets pattern filter */
void cairo_pattern_set_filter (Pattern* p, Filter f);

/** Gets pattern filter */
Filter cairo_pattern_get_filter (Pattern* p);

/** Initialize matrix */
void cairo_matrix_init (Matrix* m,
                        double xx, double yx,
                        double xy, double yy,
                        double x0, double y0);

/** Initialize matrix identity */
void cairo_matrix_init_identit (Matrix* m);

/** Initialize matrix translate */
void cairo_matrix_init_translate (Matrix* m,
                                  double tx, double ty);

/** Initialize matrix scale */
void cairo_matrix_init_scale (Matrix* m,
                              double sx, double sy);

/** Initialize matrix rotate */
void cairo_matrix_init_rotate (Matrix* m,
                               double radians);

/** Matrix translate */
void cairo_matrix_translate (Matrix* m,
                             double tx, double ty);

/** Matrix scale */
void cairo_matrix_scale (Matrix* m,
                         double sx, double sy);

/** Matrix rotate */
void cairo_matrix_rotate (Matrix* m,
                          double radians);

/** Matrix invert */
Status cairo_matrix_invert (Matrix* m);

/** Matrix multiply */
void cairo_matrix_multiply (Matrix* result,
                            Matrix* a,
                            Matrix* b);

/** Matrix transform distance */
void cairo_matrix_transform_distance (Matrix* m,
                                      double* dx,
                                      double* dy);

/** Matrix transform point */
void cairo_matrix_transform_point (Matrix* m,
                                   double* x,
                                   double* y);


